package com.hiibase.core.security.component;

import cn.hutool.core.collection.CollUtil;
import com.hibase.common.constant.RedisKeyConstant;
import com.hibase.core.redis.util.RedisUtil;
import com.hiibase.core.security.entity.UserDetail;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 授权
 */
@Component
@Slf4j
public class AccessDecisionProcessor implements AccessDecisionVoter<FilterInvocation> {

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public int vote(Authentication authentication, FilterInvocation object, Collection<ConfigAttribute> attributes) {
        assert authentication != null;
        assert object != null;

        // 拿到当前请求uri
        String requestUrl = object.getRequestUrl();
        String method = object.getRequest().getMethod();
        if(log.isDebugEnabled()){
            log.debug("进入自定义鉴权投票器，URI : {} {}", method, requestUrl);
        }

        Map map = redisUtil.hGetAll(RedisKeyConstant.CACHE_USER_ROLE_KEY);

        if(CollUtil.isEmpty(map)){
            return ACCESS_ABSTAIN;
        }
        // 当前url 需要什么权限
        List<String> list = (List<String>)map.get(requestUrl);
        if(log.isDebugEnabled()){
            log.debug("进入自定义鉴权投票器，当前url所需要的角色 : {} {}", requestUrl, list);
        }
        if(CollUtil.isEmpty(list)){
            return ACCESS_ABSTAIN;
        }
        // 拿到当前用户所具有的权限
        List<String> roles = ((UserDetail) authentication.getPrincipal()).getRoles();
        if(log.isDebugEnabled()){
            log.debug("进入自定义鉴权投票器，当前用户所拥有的角色 : {}", roles);
        }
        // 判断是否存在交集 存在交集 所以有权限
        if(CollUtil.containsAny(list,roles)){
            return ACCESS_GRANTED;
        }
        else {
            return ACCESS_DENIED;
        }
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}
